package org.one.stone.soup.grfxML.plugin.widget;

import org.one.stone.soup.grfxML.DataPoint;
import org.one.stone.soup.grfxML.DataPoints;
import org.one.stone.soup.grfxML.DataScale;
import org.one.stone.soup.grfxML.DataSize;
import org.one.stone.soup.grfxML.DataString;
import org.one.stone.soup.grfxML.GrfxMLEngine;
import org.one.stone.soup.grfxML.GrfxMLProcessor;
import org.one.stone.soup.grfxML.plugin.SimplePlugin;
import org.one.stone.soup.grfxML.plugin.grfxMLCaster;
import org.one.stone.soup.mjdb.data.field.DataLinker;

public class Spring extends SimplePlugin {

	public static final int ARG_TYPE = 0;
	public static final int ARG_CENTER = 1;
	public static final int ARG_POINTS = 2;
	public static final int ARG_K = 3;
	public static final int ARG_D = 4;

	public static final String CHAIN = "CHAIN";
	public static final String NET = "NET";

	boolean reverse;

	DataString type = new DataString();

	DataPoint center = new DataPoint();
	float vXC=0;
	float vYC=0;

	DataPoints points = new DataPoints();
	DataSize[] length = new DataSize[0];

	DataPoint[] pointA = new DataPoint[0];
	float vXA[];
	float vYA[];

	DataPoint[] pointB = new DataPoint[0];
	float vXB[];
	float vYB[];

	DataScale k = new DataScale();

	DataScale d = new DataScale();

	boolean set = false;


/**
 * Spring constructor comment.
 */
public Spring(GrfxMLEngine engine) {
	super(engine);
}
private void buildChain()
{
	if(points.size()<2)
		return;

	int loop;

	pointA = new DataPoint[points.size()-1];
	pointB = new DataPoint[points.size()-1];

	for(loop=0;loop<points.size()-1;loop++)
	{
//		System.out.println("p"+loop+"->p"+(loop+1));
		pointA[loop] = points.get(loop);
		pointB[loop] = points.get(loop+1);
	}
}
private void buildNet()
{
	if(points.size()<2)
		return;

	int pos;
	int loop;

	pointA = new DataPoint[points.size()+(points.size()/2)+(points.size()%2)];
	pointB = new DataPoint[points.size()+(points.size()/2)+(points.size()%2)];

	for(loop=0;loop<points.size();loop++)
	{
//		System.out.println("p"+loop+"->p"+((loop+1)%points.size()));
		pointA[loop] = points.get(loop);
		pointB[loop] = points.get((loop + 1)%points.size());
	}

	pos=loop;

	for(loop=0;loop<points.size()/2+(points.size()%2);loop++)
	{
//		System.out.println("p"+loop+"->p"+((loop + (points.size()/2))%points.size()));
		pointA[pos+loop] = points.get(loop);
		pointB[pos+loop] = points.get((loop + (points.size()/2))%points.size());
	}
}
/**
 * initialize method comment.
 */
public void initialize() {}
/**
 * process method comment.
 */
public void process()
{
	try{
		if(!set)
		{
			if(points==null || points.size()==0)
				return;

			if(type.getValue().equals(CHAIN))
			{
				buildChain();
			}
			else if(type.getValue().equals(NET))
			{
				buildNet();
			}

			vXA = new float[pointA.length];
			vYA = new float[pointA.length];
			vXB = new float[pointA.length];
			vYB = new float[pointA.length];

			length = new DataSize[pointA.length];

			for(int loop=0;loop<pointA.length;loop++)
			{
				length[loop] = new DataSize();
				length[loop].setValue(GrfxMLProcessor.distance(pointA[loop],pointB[loop]),this);

				vXA[loop]=0;
				vYA[loop]=0;
				vXB[loop]=0;
				vYB[loop]=0;
			}

			if(k==null)
			{
				k = new DataScale();
				k.setValue((float)0.03,this);
			}
			if(d==null)
			{
				d = new DataScale();
				d.setValue((float)0.95,this);
			}

			set=true;
		}

		int ol;
		int l;
		float dl;
		float dX;
		float dY;

//-------------------------------------------


//-------------------------------------------
	if(reverse)
	{
	for(int loop=pointA.length-1;loop>=0;loop--)
	{

		ol = length[loop].getValue();
		l =  GrfxMLProcessor.distance(pointA[loop],pointB[loop]);

		dl = l-ol;

		dX = (float)(pointB[loop].getValueX()-pointA[loop].getValueX());
		dY = (float)(pointB[loop].getValueY()-pointA[loop].getValueY());

		dX = (float)(dX * k.getValue() *(dl/ol));
		dY = (float)(dY * k.getValue() *(dl/ol));

		vXB[loop]+=dX;
		vYB[loop]+=dY;

		vXB[loop]*=d.getValue();
		vYB[loop]*=d.getValue();

//-------------------------------------------

		vXA[loop]-=dX;
		vYA[loop]-=dY;

		vXA[loop]*=d.getValue();
		vYA[loop]*=d.getValue();

//--------------------------------------------
		pointA[loop].setValueX( (int)(pointA[loop].getValueX() - vXA[loop]) ,this);
		pointA[loop].setValueY( (int)(pointA[loop].getValueY() - vYA[loop]) ,this);

		pointB[loop].setValueX( (int)(pointB[loop].getValueX() - vXB[loop]) ,this);
		pointB[loop].setValueY( (int)(pointB[loop].getValueY() - vYB[loop]) ,this);

	}

		reverse=false;
	}
	else
	{

	for(int loop=0;loop<pointA.length;loop++)
	{

		ol = length[loop].getValue();
		l =  GrfxMLProcessor.distance(pointA[loop],pointB[loop]);

		dl = l-ol;

		dX = (float)(pointB[loop].getValueX()-pointA[loop].getValueX());
		dY = (float)(pointB[loop].getValueY()-pointA[loop].getValueY());

		dX = (float)(dX * k.getValue() *(dl/ol));
		dY = (float)(dY * k.getValue() *(dl/ol));

		vXB[loop]+=dX;
		vYB[loop]+=dY;

		vXB[loop]*=d.getValue();
		vYB[loop]*=d.getValue();

//-------------------------------------------

		vXA[loop]-=dX;
		vYA[loop]-=dY;

		vXA[loop]*=d.getValue();
		vYA[loop]*=d.getValue();

//--------------------------------------------
		pointA[loop].setValueX( (int)(pointA[loop].getValueX() - vXA[loop]) ,this);
		pointA[loop].setValueY( (int)(pointA[loop].getValueY() - vYA[loop]) ,this);

		pointB[loop].setValueX( (int)(pointB[loop].getValueX() - vXB[loop]) ,this);
		pointB[loop].setValueY( (int)(pointB[loop].getValueY() - vYB[loop]) ,this);

	}

	reverse=true;
	}

/*	for(int loop=0;loop<vXA.length;loop++)
	{
		vXC += vXA[loop]+vXB[loop];
		vYC += vYA[loop]+vYB[loop];
	}

	center.setValueX( (int)(center.getValueX()+vXC) ,this);
	center.setValueY( (int)(center.getValueY()+vYC) ,this);*/

	}
	catch(Exception e)
	{
		e.printStackTrace();
	}
}
/**
 * register method comment.
 */
public void register(DataLinker store)
{
	type 	=	grfxMLCaster.cast(type,getArg(type,ARG_TYPE,store));
	center 	=	grfxMLCaster.cast(center,getArg(center,ARG_CENTER,store));
	points 	=	grfxMLCaster.cast(points,getArg(points,ARG_POINTS,store));
	k =			grfxMLCaster.cast(k,getArg(k,ARG_K,store));
	d =			grfxMLCaster.cast(d,getArg(d,ARG_D,store));
}
/**
 * replace method comment.
 */
public void replace(org.one.stone.soup.mjdb.data.field.Field oldObj, org.one.stone.soup.mjdb.data.field.Field newObj)
{
	type =		grfxMLCaster.replace(type,oldObj,newObj);
	center =	grfxMLCaster.replace(center,oldObj,newObj);
	points =	grfxMLCaster.replace(points,oldObj,newObj);
	k =			grfxMLCaster.replace(k,oldObj,newObj);
	d =			grfxMLCaster.replace(d,oldObj,newObj);
}
/**
 * stop method comment.
 */
public void stop() {}
}
